package database

import (
	"fmt"
	"sync"
	"time"

	"gitee.com/xxhsjp/x-core/conf"
	"gitee.com/xxhsjp/x-core/model"
	"gitee.com/xxhsjp/x-core/utils/xstrings"
	"github.com/pkg/errors"
	"github.com/sirupsen/logrus"
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
)

var mum sync.RWMutex
var mysqlDbs = make(map[string]*gorm.DB)

func DB(dsName ...string) *gorm.DB {
	var ds string
	if len(dsName) > 0 {
		ds = dsName[0]
	} else {
		ds = "mysql"
	}

	return newDB(ds)
}

func newDB(ds string) *gorm.DB {
	mum.RLock()
	if _, ok := mysqlDbs[ds]; ok {
		mum.RUnlock()
		return mysqlDbs[ds]
	}
	mum.RUnlock()

	mum.Lock()
	defer mum.Unlock()
	if _, ok := mysqlDbs[ds]; !ok {
		mysqlDbs[ds] = initMysql(mysqlConfig(ds))
	}

	return mysqlDbs[ds]
}

func initMysql(conf *model.MysqlConfig) *gorm.DB {
	conn := fmt.Sprintf("%s:%s@%s(%s:%d)/%s?charset=utf8&parseTime=True&loc=Local&timeout=5s",
		conf.User, conf.Passwd, conf.NetWork, conf.Server, conf.Port, conf.DbName)
	db, err := gorm.Open(mysql.Open(conn), &gorm.Config{})
	logrus.Debug("conn: ", conn)
	if err != nil {
		logrus.Errorf("%+v", errors.WithStack(err))
		panic(err)
	}
	sqlDB, err := db.DB()
	if err != nil {
		logrus.Errorf("%+v", errors.WithStack(err))
		panic(err)
	}
	sqlDB.SetConnMaxLifetime(time.Duration(conf.ConnMaxLifetime) * time.Second) // 每个连接的存活時間
	sqlDB.SetMaxOpenConns(conf.MaxOpenConns)                                    // 最大连接数
	sqlDB.SetMaxIdleConns(conf.MaxIdleConns)                                    // 最大空闲连接数
	return db
}

func mysqlConfig(ds string) *model.MysqlConfig {
	c := model.MysqlConfig{MaxOpenConns: 100, MaxIdleConns: 10, ConnMaxLifetime: 30}
	viper := conf.Wrapper

	err := viper.UnmarshalKey(ds, &c)
	if err != nil {
		logrus.Errorf("%+v", errors.WithStack(err))
		panic(err)
	}
	if xstrings.IsBlank(c.Server) || xstrings.IsBlank(c.DbName) || c.Port == 0 {
		err := "mysql config is invalid"
		logrus.Errorf("%+v", errors.New(err))
		panic(err)
	}
	pwd, err := viper.GetDecryptedString(c.Passwd, true)
	if err != nil {
		logrus.Errorf("%+v", errors.WithStack(err))
		panic(err)
	}
	c.Passwd = pwd
	logrus.Debugf("mysql config[%s]: %+v", ds, c)
	return &c
}
